<?php
	include("maintenance_config.inc");
/*  XML parser for the NIST's National Vulnerability Database (NVD)
*   Open Source license, NCSA/U. of Illinois
*   Version 1.01, September 2, 2005
*   Pascal Meunier
*   Purdue University CERIAS
*   Contact: pmeunier 

*  Uses the basic XML parser included with PHP
*  that doesn't perform schema validation
*   see http://us2.php.net/xml
*
*  The NVD's XML schema doesn't have conflicting name tags
*  at various nesting levels, so its parsing is relatively 
*  simple.  Therefore, a flat namespace (independent of nesting level)
*  works fine.  This simple approach doesn't work, for example, with Microsoft's
*  XML export of vulnerabilities.

*  Note that this parser does not have cases for all tags in the NVD schema.
*  Simply add "case" statements for the additional tags that matter to you.
*
*  The data from parsing needs further validation or escaping if it is 
*  to be inserted into another database.

*  -Replace the first line with the path to your installation of PHP
*  for command line execution.  Delete the path to PHP on the first line for 
*  execution with an Apache web server.
*  -Choose a source for the XML file (see below)

*ChangeLog:
* 1.0 first version August 29, 2005
* 1.01 September 2, 2005
   -Changed the name nvdcve-1999-2002.xml to nvdcve-2002.xml to match nvd changes
   -Removed comment "from Apache" regarding https locations, as they work from the command line too, depending on how PHP was installed
   -Now uses command line argument if present as XML source
   -Now captures the content of <REF> tags
*/

error_reporting (E_ALL);

$debug = true; // will print messages about every field found if true
$count_entries = 0; // count number of new CVE entries found today

$patterns = array('/\'/', '/\\\/');
$replace = array("''", '\\\\\\');

// Choose a source for parsing
// Check if a source was passed as argument
if (isset($argv[1])) {
   parse_this($argv[1]);
} else {
	//parse_this("cve-recent.xml");
	parse_this("test.xml");
	//parse_this("test2.xml");
   //parse_this("http://nvd.nist.gov/download/nvdcve-modified.xml");
   // other possibilities:
   //parse_this("http://nvd.nist.gov/download/nvdcve-2002.xml");
   //parse_this("http://nvd.nist.gov/download/nvdcve-2003.xml");
   //parse_this("http://nvd.nist.gov/download/nvdcve-2004.xml");
   //parse_this("http://nvd.nist.gov/download/nvdcve-2009.xml");
   //parse_this("http://nvd.nist.gov/download/nvdcve-2010.xml");
   //
   // The following do not work with vanilla PHP installs 
   // without the wrapper "https" (e.g., MacOS X default install)
   //parse_this("https://nvd.nist.gov/download/nvdcve-2002.xml");
   //parse_this("https://nvd.nist.gov/download/nvdcve-2003.xml");
   //parse_this("https://nvd.nist.gov/download/nvdcve-2004.xml");
   //parse_this("https://nvd.nist.gov/download/nvdcve-2005.xml");
   //parse_this("https://nvd.nist.gov/download/nvdcve-2006.xml");
}

//echo "<br>Found $count_entries entries in this NVD location<br><br>";
//print_r($cve);
//insert_to_database();
die; // not necessary, added for clarity

function startElement($parser, $name, $attrs) {
   global $all_data, $CVE, $debug, $insert, $vendor, $product, $count_entries, $desc_type;
   global $cve, $ver, $patterns, $replace;
   global $dbhost, $dbuser, $dbpass, $dbname;
   if ($debug) {
      //echo "processing tag named '$name'<br>";
   }
   //
   // the switch statement should enumerate all of the possible name tags.
   // State is kept using global variables, so that nested tags can
   // access their context.
   //
   switch ($name) {
      case 'ENTRY':
         //$count_entries++;
         // get name and publication date
		 $CVE = validate_CVE($attrs['NAME']);
         // other attributes, such as severity, are available
         // see http://nvd.nist.gov/download/nvdcve-xmldoc.cfm
         if ($debug) {
            //echo "found CVE entry $CVE with publication date ". $published."<br>";
			$cve[$count_entries][0] = $CVE;
		    $cve[$count_entries][1] = validate_date($attrs['PUBLISHED']);
			$cve[$count_entries][2] = substr($attrs['PUBLISHED'], 0, 4);
			$cve[$count_entries][3] = $attrs['SEVERITY'];
			$cve[$count_entries][4] = $attrs['CVSS_BASE_SCORE'];
			$cve[$count_entries][5] = $attrs['CVSS_EXPLOIT_SUBSCORE'];
			$cve[$count_entries][6] = $attrs['CVSS_IMPACT_SUBSCORE'];
         }
         break;
      case 'DESCRIPT':
         // if there ever was more than one type of description
         // remember which source with a global
         // NVD or CVE
         $desc_type = $attrs['SOURCE'];
         // reset data accumulator
         $all_data = '';
         // need to wait for end tag to get contents
         break;
      case 'PROD':
         $vendor = $attrs['VENDOR'];
         $product = $attrs['NAME'];
		 $ver = '';
         if ($CVE == '') {
            echo "error, no CVE number";
            die;
         }
         if ($debug) {
            //echo "found vendor $vendor";
            //echo " found product $product<br>";
			$cve[$count_entries][8][] = preg_replace($patterns, $replace, $vendor);
			$cve[$count_entries][9][] = preg_replace($patterns, $replace, $product);
         }
         if ($vendor == "") {
            // this happens
            echo "NVD integrity alert: no vendor for product $product, CVE is $CVE<br>";
         }
         if ($product == "") {
            echo "NVD integrity alert: no product, CVE is $CVE<br>";
         }
         break;
      /*case 'LOSS_TYPES':
         break;
      case 'VULNS_TYPES':
         break;
      case 'REF':
         // source, url, etc...
         if ($debug) {
            echo " reference from ". $attrs['SOURCE'];
            echo " is available at ". $attrs['URL'];
            echo "<br>";
         }
         $all_data = '';
         // need to wait for end tag to get contents
         break;*/
      case 'VERS':
         if ($debug) {
            //echo " version ". $attrs['NUM'];
            //echo " of product $product is vulnerable<br>";
			if( isset($attrs['EDITION']) )
				$ver .= $attrs['NUM'].' edition '.$attrs['EDITION'].';';
			else
				$ver .= $attrs['NUM'].';';
         }
         break;
	  case 'NVD':
		 mysql_connect( $dbhost, $dbuser, $dbpass ) or die("cant connect to database.");
		 mysql_select_db($dbname) or die("cant select database $dbname.");
		 $query = "SELECT last_update FROM last_update";
		 $buffer = mysql_query($query);
		 $last_update = mysql_fetch_assoc($buffer);
		 $last_update = $last_update['last_update'];
		 
		 echo "last_update: ".$last_update."<br>";
		 echo "public_date: ".$attrs['PUB_DATE']."<br>";
		 
		 if( $attrs['PUB_DATE'] >= $last_update ){ 
			$count_entries = 0;
			unset($GLOBALS['cve']);
			$query = "UPDATE last_update SET last_update = '".$attrs['PUB_DATE']."'";
			mysql_query($query);
		 }
		 else{
			echo("<script>window.open('', '_self', ''); window.close();</script>");
			die;
		 }
		 break;
      case '':
         break;
   }
}

function endElement($parser, $name) {
   global $all_data, $CVE, $debug;
   global $cve, $ver, $patterns, $replace, $count_entries;
   switch ($name) {
      case 'ENTRY':
		 $count_entries++;
		 echo "finished parsing $CVE.<br>";
         //$CVE = '';
         break;
      case 'DESCRIPT':
         if ($CVE == '') {
            echo "error, no CVE number";
            die;
         }
         if ($debug) {
            //echo "found description $all_data<br> for CVE entry $CVE<br>";
			$cve[$count_entries][7] = preg_replace($patterns, $replace, $all_data);
			//print_r($cve);
         }
            
         // reset data accumulator
         $all_data = '';
         break;
      /*case 'REF':
         if ($debug) {
            echo "found reference content '$all_data'<br> for CVE entry $CVE<br>";
         }            
         // reset data accumulator
         $all_data = '';
         break;
      case 'AVAIL':
         if ($debug) {
            echo "loss type is availability<br>";
         }
         break;
      case 'CONF':
         if ($debug) {
            echo "loss type is confidentiality<br>";
         }
         break;
      case 'INT':
         if ($debug) {
            echo "loss type is integrity<br>";
         }
         break;
      case 'SEC_PROT':
         if ($debug) {
            echo "loss type is security protection<br>";
         }
         break;
      case 'ACCESS':
         if ($debug) {
            echo "vulnerability type is access<br>";
         }
         break;
      case 'INPUT':
         if ($debug) {
            echo "vulnerability type is input<br>";
         }
         break;
      case 'DESIGN':
         if ($debug) {
            echo "vulnerability type is design<br>";
         }
         break;
      case 'EXCEPTION':
         if ($debug) {
            echo "vulnerability type is exception<br>";
         }
         break;
      case 'ENV':
         if ($debug) {
            echo "vulnerability type is environment<br>";
         }
         break;
      case 'CONFIG':
         if ($debug) {
            echo "vulnerability type is configuration<br>";
         }
         break;
      case 'RACE':
         if ($debug) {
            echo "vulnerability type is race<br>";
         }
         break;
      case 'OTHER':
         if ($debug) {
            echo "vulnerability type is other<br>";
         }
         break;
      case 'REMOTE':
         if ($debug) {
            echo "vulnerability range is remote<br>";
         }
         break;
      case 'LOCAL':
         if ($debug) {
            echo "vulnerability range is local<br>";
         }
         break;
      case 'USER_INIT':
         if ($debug) {
            echo "vulnerability range is through a user<br>";
         }
         break;*/
	  case 'PROD':
		 if($debug) {
			$cve[$count_entries][10][] = preg_replace($patterns, $replace, $ver);
		 }
		 break;
	  case 'NVD':
		  if($debug){
		    echo "<br>Found $count_entries entries in this NVD location<br><br>";
			distributer();
			//$c = json_encode($cve);
			//$num_c = $count_entries;
			//echo $c;
			//header("Location: distributer.php?c=$c&num_c=$num_c");
		  }
		  break;
      case '':
         break;
   }
}

function characterData($parser, $data) {
   global $all_data;
   // concatenate due to bug with & according to a user entry in PHP docs
   // entry by sam at cwa dot co dot nz, Sept 2000
   // This issue might have been fixed later.  The fix can't hurt though.
   $all_data .= $data;
}

function parse_this($url) {
   // code for this function is from http://us2.php.net/xml
   $xml_parser = xml_parser_create();
   // use case-folding so we are sure to find the tag in $map_array
   xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, true);
   xml_set_element_handler($xml_parser, "startElement", "endElement");
   xml_set_character_data_handler($xml_parser, "characterData");
   if (!($fp = fopen($url, "r"))) {
      die("could not open XML input");
   }
   while ($data = fread($fp, 4096)) {
      if (!xml_parse($xml_parser, $data, feof($fp))) {
          die(sprintf("XML error: %s at line %d",
                      xml_error_string(xml_get_error_code($xml_parser)),
                      xml_get_current_line_number($xml_parser)));
      }
   }
   xml_parser_free($xml_parser);
}

function validate_CVE($input) {
   // expecting something like CAN-2004-0002
   // NVD documentation suggests this reg exp,
   // (http://nvd.nist.gov/download/nvdcve-xmldoc.cfm)
   // (CAN|CVE)-/d/d/d/d-/d/d/d/d
   // which doesn't work.  See below
   if (preg_match('/(CAN|CVE)-\d\d\d\d-\d\d\d\d/', $input, $matches)) {
      return $matches[0];
   } else {
      // if there was an error (false) or if 0 matches
      die ("Invalid CVE number encountered: $input"); 
   }
}

function validate_Date($input) {
   // expecting something like 2004-03-03
   if (preg_match('/\d\d\d\d-\d\d-\d\d/', $input, $matches)) {
      return $matches[0];
   } else {
      // if there was an error (false) or if 0 matches
      die ("Invalid date encountered: $input"); 
   }
}

function distributer(){
	global $cve, $count_entries;
	include("distributer.php");

}

/*
index of $cve[]
0 - cvename
1 - published
2 - year
3 - severity
4 - cvss
5 - cvss_exp
6 - cvss_imp
7 - description
8 - vendor
9 - product
10 - versions
*/

?> 